package com.hare.auth.config;

import com.hare.auth.exception.FailAccessDeniedHandler;
import com.hare.auth.exception.FailAuthenticationEntryPoint;
import com.hare.auth.filter.JwtAuthenticationTokenFilter;
import com.hare.auth.utils.JwtUtils;
import com.hare.common_redis.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

/**
 * @program: Hare
 * @description: springSecurity 配置类
 * @author: Hare
 * @create: 2022-06-05 20:01
 * @Version 6.0.1
 **/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    @Autowired
    RedisCache redisCache;

    @Autowired
    JwtUtils jwtUtils;


    /**
     * 自定义userDetails
     */
    @Autowired
    UserDetailsService userDetailsService;


    /**
     * 装载BCrypt密码编码器
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 认证失败处理类
     */
    @Autowired
    private FailAuthenticationEntryPoint authenticationEntryPoint;


    /**
     * 授权失败处理
     */
    @Autowired
    private FailAccessDeniedHandler failAccessDeniedHandler;



    /**
     * 管理器
     *
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager authenticationManagerBean(UserDetailsService userDetailsService,PasswordEncoder passwordEncoder) throws Exception {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder);
        return new ProviderManager(provider);
    }



    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // 认证授权失败处理
        http.csrf((csrf) -> csrf.disable())
                .exceptionHandling(exceptionHandling -> {
                    exceptionHandling.authenticationEntryPoint(authenticationEntryPoint);
                    exceptionHandling.accessDeniedHandler(failAccessDeniedHandler);
                });

        // 放行资源配置
        http.authorizeHttpRequests(authorize -> {
            authorize.requestMatchers("/auth/login", "/auth/loginOut").permitAll()
                    .requestMatchers(HttpMethod.GET, "/", "/*.html", "/**.html", "/**.css", "/**.js", "/profile/**").permitAll()
                    .requestMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs").permitAll()
                    .anyRequest().authenticated();
        }).headers(headers -> {
            headers.frameOptions(frameOptions -> frameOptions.disable());
        });

        // jwt过滤器
        http.addFilterAfter(new JwtAuthenticationTokenFilter(redisCache,jwtUtils), UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers(
                AntPathRequestMatcher.antMatcher("/auth/**")
        );
    }

}
